package com.javalab.recorder.audio;

import java.io.ByteArrayOutputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

import org.apache.log4j.Logger;

public class AudioCaptureThread implements Callable<byte[]> {

	private TargetDataLine targetDataLine;

	private AudioFormat audioFormat;

	private Future<byte[]> future;

	private boolean recording;

	private static Logger logger = Logger.getLogger(AudioCaptureThread.class);

	public AudioCaptureThread(TargetDataLine targetDataLine, AudioFormat audioFormat) {
		this.targetDataLine = targetDataLine;
		this.audioFormat = audioFormat;
	}

	public void startCapturing() {
		try {
			targetDataLine.open(audioFormat);
			FutureTask<byte[]> futureTask = new FutureTask<byte[]>(this);
			Thread thread = new Thread(futureTask);
			future = futureTask;
			recording = true;
			targetDataLine.start();
			thread.start();
		} catch (LineUnavailableException e) {
			logger.error(e.getMessage(), e);
		}
	}

	public byte[] stopCapturing() {
		try {
			recording = false;
			targetDataLine.stop();
			targetDataLine.close();
			return future.get();
		} catch (InterruptedException e) {
			logger.error(e.getMessage(), e);
		} catch (ExecutionException e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

	@Override
	public byte[] call() throws Exception {
		ByteArrayOutputStream bao = null;
		try {
			bao = new ByteArrayOutputStream();
			AudioInputStream ais = new AudioInputStream(targetDataLine);
			byte[] buffer = new byte[targetDataLine.getBufferSize() / 5];
			int count = -1;
			while ((count = ais.read(buffer, 0, buffer.length)) > 0 || recording) {
				bao.write(buffer, 0, count);
			}
			return bao.toByteArray();
		} finally {
			bao.close();
		}
	}

}
